package cn.kgc.easybuy.controller;

import cn.kgc.easybuy.config.MyAlipayConfig;
import cn.kgc.easybuy.config.MyWXpayConfig;
import cn.kgc.easybuy.pojo.Order;
import cn.kgc.easybuy.pojo.OrderDetial;
import cn.kgc.easybuy.service.OrderService;
import cn.kgc.easybuy.utils.AjaxResult;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayConfig;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.wechat.pay.java.core.exception.ValidationException;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import com.wechat.pay.java.service.payments.nativepay.model.Amount;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/ali")
public class ProductPayByController {
    @Autowired
    private MyAlipayConfig ac;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private OrderService orderService;

    private static final Logger logger = LoggerFactory.getLogger(ProductPayByController.class);



    @GetMapping("/payByZfb/{id}")
    public void payByZfb(@PathVariable Integer id, HttpServletResponse response, HttpServletRequest request) throws AlipayApiException, IOException {
        System.out.println(ac.getGatewayUrl()+ac.getAppId()+ ac.getMerchantPrivateKey()+ "json"+ ac.getCharset()+ ac.getAlipayPublicKey()+ ac.getSignType());
        //获得初始化的AlipayClient
        AlipayClient alipayClient = new DefaultAlipayClient(ac.getGatewayUrl(), ac.getAppId(), ac.getMerchantPrivateKey(), "json", ac.getCharset(), ac.getAlipayPublicKey(), ac.getSignType());

        //设置请求参数

        //PC版页面支付对象
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();

        //手机版页面支付对象
//        AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();

        //设置同步回调地址
        alipayRequest.setReturnUrl(ac.getReturnUrl());
        //设置异步回调地址
        alipayRequest.setNotifyUrl(ac.getNotifyUrl());

        //获取订单数据
        Order order = orderService.selectOrderById(id);

        //商户订单号，商户网站订单系统中唯一订单号，必填
        String out_trade_no = order.getSerialNumber();
        //付款金额，必填
        String total_amount = order.getCost().toString();
        //订单名称，必填
        String subject = order.getLoginName()+"的订单";
        //商品描述，可空
        String body =order.getLoginName()+"的订单";

        alipayRequest.setBizContent("{\"out_trade_no\":\"" + out_trade_no +"\","
                + "\"total_amount\":\""+ total_amount +"\","
                + "\"subject\":\""+ subject +"\","
                + "\"body\":\""+ body +"\","
                + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
        //请求
        String result = alipayClient.pageExecute(alipayRequest).getBody();

        response.setContentType("text/html");
        response.setCharacterEncoding("UTF-8");
        response.getWriter().write(result);
        response.getWriter().flush();
    }

    @RequestMapping("/notify_url")
    public void notify_url(HttpServletRequest request, HttpServletResponse response) throws IOException, AlipayApiException {
        System.out.println("异步回调开始执行");
        //获取支付宝POST过来反馈信息
        Map<String,String> params = new HashMap<String,String>();
        Map<String,String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }

        boolean signVerified = AlipaySignature.rsaCheckV1(params, ac.getAlipayPublicKey(), ac.getCharset(), ac.getSignType()); //调用SDK验证签名

        //——请在这里编写您的程序（以下代码仅作参考）——

        /* 实际验证过程建议商户务必添加以下校验：
        1、需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号，
        2、判断total_amount是否确实为该订单的实际金额（即商户订单创建时的金额），
        3、校验通知中的seller_id（或者seller_email) 是否为out_trade_no这笔单据的对应的操作方（有的时候，一个商户可能有多个seller_id/seller_email）
        4、验证app_id是否为该商户本身。
        */
        response.setContentType("text/html");
        response.setCharacterEncoding("UTF-8");
        PrintWriter out = response.getWriter();
        out.println("<h1>支付完成  异步</h1>");
        if(signVerified) {//验证成功
            //商户订单号
            String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");

            //支付宝交易号
            String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");

            //交易状态
            String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"),"UTF-8");

            // 通过订单号获取Redis订单信息
            Integer id= (Integer) redisTemplate.opsForValue().get("order:"+out_trade_no);
            Order order = orderService.selectOrderById(id);

            if(trade_status.equals("TRADE_FINISHED")){
                //判断该笔订单是否在商户网站中已经做过处理  TRADE_FINISHED标识交易结束，不可退款状态
                if (order.getState()==3){
                    //如果有做过处理，不执行商户的业务程序
                }else {
                    //如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序,订单切换至已完成状态
                    order.setState(3);
                    orderService.updateOrder(order);
                }
                //注意：
                //退款日期超过可退款期限后（如三个月可退款），支付宝系统发送该交易状态通知
                System.out.println("交易关闭！");
            }else if (trade_status.equals("TRADE_SUCCESS")){
                //判断该笔订单是否在商户网站中已经做过处理
                //如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
                //如果有做过处理，不执行商户的业务程序
                if (order.getState()==0){
                    //未付款状态
                    order.setState(1);
                    order.setTranscantionId(trade_no);
                    order.setPayTime(new Date());
                    order.setPayBy(0);
                    orderService.sellOrder( order);
                    orderService.updateOrder(order);
                    redisTemplate.delete(out_trade_no);
                    System.out.println("付款成功！");
                }else {
                    //已付款状态
                }
                //注意：
                //付款完成后，支付宝系统发送该交易状态通知
                System.out.println("付款完成！");

            }

            out.println("success");

        }else {//验证失败
            out.println("fail");
            System.out.println("验证失败");
            //调试用，写文本函数记录程序运行情况是否正常
            //String sWord = AlipaySignature.getSignCheckContentV1(params);
            //MyAlipayConfig.logResult(sWord);
        }
        out.flush();
        out.close();
        System.out.println("异步回调执行完成");
    }

    @RequestMapping("/return_url")
    public void return_url(HttpServletRequest request,HttpServletResponse response) throws IOException, AlipayApiException {
        System.out.println("同步回调执行");
        //获取支付宝GET过来反馈信息
        Map<String,String> params = new HashMap<String,String>();
        Map<String,String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }

        //调用SDK验证签名
        boolean signVerified = AlipaySignature.rsaCheckV1(params, ac.getAlipayPublicKey(), ac.getCharset(), ac.getSignType());

        //——请在这里编写您的程序（以下代码仅作参考）——
        response.setContentType("text/html");
        response.setCharacterEncoding("UTF-8");
        PrintWriter out = response.getWriter();

        if(signVerified) {


            out.println("<h1>支付完成</h1>");
            //商户订单号
            String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");

            //支付宝交易号
            String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");

            //付款金额
            String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"),"UTF-8");


            out.println("支付宝交易号:"+trade_no+"<br/>商户订单号:"+out_trade_no+"<br/>付款金额:"+total_amount);

            out.println("<a href='http://localhost:5050/#/user?tab=order&scope=self'>返回</a>");
        }else {
            out.println("验签失败");
        }
        response.sendRedirect("http://localhost:5050/#/user?tab=order&scope=self");
        System.out.println("同步回调执行完成");

        out.flush();
        out.close();
    }



    @GetMapping("/refundByZfb/{id}")
    public void  refundByZfb(@PathVariable Integer id,HttpServletResponse response1) throws AlipayApiException, IOException {
        response1.setContentType("text/html");
        response1.setCharacterEncoding("UTF-8");
        PrintWriter pw = response1.getWriter();
        
        try {
            // 初始化SDK
            AlipayClient alipayClient = new DefaultAlipayClient(getAlipayConfig());

            // 构造请求参数以调用接口
            AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
            AlipayTradeRefundModel model = new AlipayTradeRefundModel();

            Order order = orderService.selectOrderById(id);
            
            // 检查订单创建时间是否在30天内
            if (order.getCreateTime() != null) {
                long currentTime = System.currentTimeMillis();
                long orderTime = order.getCreateTime().getTime();
                long thirtyDaysInMillis = 30L * 24 * 60 * 60 * 1000; // 30天的毫秒数
                
                if (currentTime - orderTime > thirtyDaysInMillis) {
                    // 订单超过30天，不能退款
                    pw.println("<h1>退款失败</h1>");
                    pw.println("<p>订单创建时间超过30天，无法退款。</p>");
                    pw.println("<p>订单创建时间: " + order.getCreateTime() + "</p>");

                    pw.flush();
                    pw.close();
                    return;
                }
            }
            
            // 检查订单状态，只有已支付的订单才能退款
            if (order.getState() != 1) {
                pw.println("<h1>退款失败</h1>");
                pw.println("<p>订单状态不正确，无法退款。</p>");
                pw.println("<p>当前订单状态: " + order.getState() + "(0未付款 1已付款 2已取消 3已完成 4已退款)</p>");
                if (order.getState() == 0) {
                    pw.println("<p>订单尚未支付，请确认是否已完成支付流程。</p>");
                }
                pw.flush();
                pw.close();
                response1.sendRedirect("http://localhost:5050/#/user?tab=order&scope=self");
                return;
            }
            
            // 检查是否已设置支付宝交易号
            if (order.getTranscantionId() == null || order.getTranscantionId().isEmpty()) {
                pw.println("<h1>退款失败</h1>");
                pw.println("<p>订单缺少支付宝交易号，无法执行退款。</p>");
                pw.println("<p>这可能是因为支付流程未完全完成，请联系客服处理。</p>");
                pw.flush();
                pw.close();
                response1.sendRedirect("http://localhost:5050/#/user?tab=order&scope=self");
                return;
            }

            // 获取订单详情列表
            List<OrderDetial> orderDetails = order.getOrderDetialList();
            if (orderDetails == null || orderDetails.isEmpty()) {

            }

            String out_trade_no = order.getSerialNumber();
            String trade_no = order.getTranscantionId();
            
            // 设置商户订单号
            model.setOutTradeNo(out_trade_no);

            // 设置支付宝交易号
            model.setTradeNo(trade_no);

            // 设置退款金额
            model.setRefundAmount(order.getCost().toString());

            // 设置退款原因说明
            model.setRefundReason("正常退款");

            // 设置退款请求号，使用订单号+时间戳确保唯一性
            model.setOutRequestNo(out_trade_no + System.currentTimeMillis());

            request.setBizModel(model);

            System.out.println("准备发起退款请求，订单号: " + out_trade_no + ", 交易号: " + trade_no);
            AlipayTradeRefundResponse response = alipayClient.execute(request);
            
            // 记录支付宝返回的完整响应，便于调试
            System.out.println("支付宝退款接口响应: " + response.getBody());

            if (response.isSuccess()) {
                System.out.println("退单成功");

                //更新订单状态为已退款
                order.setState(4);// 假设4代表已退款状态
                order.setRefundTime(new Date());// 设置退款时间
                orderService.refundOrder( order);
                orderService.updateOrder(order);

                pw.println("<h1>退单成功</h1>");
                pw.println("<h2>订单信息</h2>");
                pw.println("商户订单号："+out_trade_no+"<br/>");
                pw.println("支付宝交易号："+trade_no+"<br/>");
                pw.println("退款金额："+order.getCost()+"<br/><br/>");
                
                pw.println("<h2>订单详情</h2>");
                pw.println("<table border='1' cellspacing='0'>");
                pw.println("<tr><th>商品名称</th><th>单价</th><th>数量</th><th>小计</th></tr>");
                
                if (orderDetails != null && !orderDetails.isEmpty()) {
                    for (OrderDetial detail : orderDetails) {
                        pw.println("<tr>");
                        pw.println("<td>" + detail.getProductName() + "</td>");
                        pw.println("<td>" + detail.getProductPrice() + "</td>");
                        pw.println("<td>" + detail.getQuantity() + "</td>");
                        pw.println("<td>" + detail.getCost() + "</td>");
                        pw.println("</tr>");
                    }
                } else {
                    pw.println("<tr><td colspan='4'>无订单详情信息</td></tr>");
                }
                
                pw.println("</table><br/>");
                pw.println("<p>交易详情："+response.getBody()+"</p>");

            } else {
                System.out.println("退单失败，错误代码: " + response.getCode() + 
                                "，子错误代码: " + response.getSubCode() + 
                                "，错误信息: " + response.getSubMsg());
                
                pw.println("<h1>退单失败</h1>");
                
                // 根据错误代码提供具体错误信息
                if ("ACQ.TRADE_HAS_CLOSE".equals(response.getSubCode())) {
                    pw.println("<p><strong>错误信息：交易已经关闭，无法退款</strong></p>");
                    pw.println("<ul>");
                    pw.println("<li>商户订单号：" + out_trade_no + "</li>");
                    pw.println("<li>支付宝交易号：" + trade_no + "</li>");
                    pw.println("<li>订单创建时间：" + order.getCreateTime() + "</li>");
                    if (order.getPayTime() != null) {
                        pw.println("<li>支付完成时间：" + order.getPayTime() + "</li>");
                    }
                    pw.println("</ul>");
                } else if ("ACQ.REASON_TRADE_REFUND_FAIL".equals(response.getSubCode())) {
                    pw.println("<p>错误信息：退款失败</p>");
                    pw.println("<p>详细信息：" + response.getSubMsg() + "</p>");
                } else if ("ACQ.TRADE_NOT_EXIST".equals(response.getSubCode())) {
                    pw.println("<p>错误信息：交易不存在</p>");
                    pw.println("<p>详细信息：系统找不到对应的支付宝交易记录</p>");
                } else {
                    pw.println("<p>错误码：" + response.getCode() + "</p>");
                    pw.println("<p>错误信息：" + response.getMsg() + "</p>");
                    pw.println("<p>详细错误信息：" + response.getSubMsg() + "</p>");
                }
                
                pw.println("<hr>");
                pw.println("<h2>交易信息</h2>");
                pw.println("<p>商户订单号：" + out_trade_no + "</p>");
                pw.println("<p>支付宝交易号：" + trade_no + "</p>");
                pw.println("<p>订单创建时间：" + order.getCreateTime() + "</p>");
                if (order.getPayTime() != null) {
                    pw.println("<p>支付完成时间：" + order.getPayTime() + "</p>");
                }
            }
        } catch (Exception e) {
            System.err.println("退款过程中发生异常: " + e.getMessage());
            e.printStackTrace();
            pw.println("<h1>系统错误</h1>");
            pw.println("<p>在处理退款请求时发生系统异常</p>");
            pw.println("<p>错误信息：" + e.getMessage() + "</p>");
        }
        response1.sendRedirect("http://localhost:5050/#/user?tab=order&scope=self");
        pw.flush();
        pw.close();
    }

    private AlipayConfig getAlipayConfig() {
        String privateKey  = ac.getMerchantPrivateKey();
        String alipayPublicKey = ac.getAlipayPublicKey();
        AlipayConfig alipayConfig = new AlipayConfig();
        alipayConfig.setServerUrl(ac.getGatewayUrl());
        alipayConfig.setAppId(ac.getAppId());
        alipayConfig.setPrivateKey(privateKey);
        alipayConfig.setFormat("json");
        alipayConfig.setAlipayPublicKey(alipayPublicKey);
        alipayConfig.setCharset("UTF-8");
        alipayConfig.setSignType("RSA2");
        return alipayConfig;
    }

    @GetMapping("/payByWX/{id}")
    public AjaxResult payByWX(@PathVariable Integer id){
        // 构建service
        NativePayService service = new NativePayService.Builder().config(MyWXpayConfig.getInstance().getConfig()).build();
        // request.setXxx(val)设置所需参数，具体参数可见Request定义
        PrepayRequest request = new PrepayRequest();

        //获取订单信息
        Order order = orderService.selectOrderById(id);

        //以订单号为名字将订单id存储在redis中，使得回调函数能够获取订单id,存储时间为15min
        redisTemplate.opsForValue().set(order.getSerialNumber(),order.getId(),15,TimeUnit.MINUTES);

        Amount amount = new Amount();
        amount.setTotal(1);
        // 设置订单支付金额 单位（分）
        request.setAmount(amount);
        // 设置应用ID
        request.setAppid(MyWXpayConfig.getInstance().getAppid());
        // 设置商户ID
        request.setMchid(MyWXpayConfig.getInstance().getMerchantId());
        // 设置订单描述信息
        request.setDescription(order.getLoginName()+"的订单");
        // 设置异步回调地址
        request.setNotifyUrl(MyWXpayConfig.getInstance().getNotifyUrl());
        // 设置系统订单号
        request.setOutTradeNo(order.getSerialNumber());

        // 调用下单方法，得到应答
        PrepayResponse response = service.prepay(request);
        /**
         * 从应答中得到支付url，此url返回到前端vue，由vue生成二维码显示 并用手机扫码支付
         */
        return AjaxResult.success().add("pay_url", response.getCodeUrl());
    }


    /**
     * 异步回调
     *
     * @param signature     验签的签名值
     * @param serialNumber  验签的微信支付平台证书序列号/微信支付公钥ID
     * @param timestamp     验签的时间戳
     * @param nonce         验签的随机字符串
     * @param signatrueType 验签的算法类型
     * @param body          主体通知参数（JSON格式）
     * @param response      向应对象
     */
    @PostMapping("/wxNotify")
    public void wxNotify(@RequestHeader(value = "Wechatpay-Signature") String signature,
                         @RequestHeader(value = "Wechatpay-Serial") String serialNumber,
                         @RequestHeader(value = "Wechatpay-Timestamp") String timestamp,
                         @RequestHeader(value = "Wechatpay-Nonce") String nonce,
                         @RequestHeader(value = "Wechatpay-Signature-Type") String signatrueType,
                         @RequestBody String body,
                         HttpServletResponse response) throws IOException {
        // 创建通知解析器
        NotificationParser notificationParser = new NotificationParser(MyWXpayConfig.getInstance().getConfig());
        // 创建微信支付通知请求参数
        com.wechat.pay.java.core.notification.RequestParam requestParam = new RequestParam.Builder()
                .nonce(nonce)
                .signature(signature)
                .timestamp(timestamp)
                .serialNumber(serialNumber)
                .signType(signatrueType)
                .body(body).build();

        // 解密后封装成的对象
        Transaction transaction = null;

        try {
            transaction = notificationParser.parse(requestParam, Transaction.class);
        } catch (ValidationException e) {
            logger.error("验证签名错误！",e);
            //通知微信验证签名错误，需重新回调
            response.setStatus(500);
            return;
        }
        if (transaction.getTradeState() == Transaction.TradeStateEnum.SUCCESS) {
            /**
             * 交易成功
             * 调用系统订单业务方法，更新订单状态，以及系统后续处理
             */

            //在redis中获取当前订单成功的订单id
            Integer id =(Integer) redisTemplate.opsForValue().get(transaction.getOutTradeNo());
            Order order = orderService.selectOrderById(id);
            // 设置订单成功信息
            order.setPayTime(new Date());
            order.setTranscantionId(transaction.getTransactionId());
            order.setState(1);
            order.setPayBy(1);
            orderService.sellOrder(order);
            orderService.updateOrder( order);
            redisTemplate.delete(transaction.getOutTradeNo());
            logger.info(String.format("商户下单时传入的商户系统内部订单号[%s]", transaction.getOutTradeNo()));
            logger.info(String.format("微信支付侧订单的唯一标识[%s]", transaction.getTransactionId()));
        }
        logger.info(transaction.toString());
        //通知微信回调成功
        response.setStatus(200);
        response.getWriter().write("OK");
        response.sendRedirect("http://localhost:5050/#/user?tab=order&scope=self");
        response.getWriter().flush();
    }
}
